package org.komarichin.struts2.actions;


import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.komarichin.beans.IFile;
import org.komarichin.beans.service.IFileService;
import org.komarichin.struts2.BaseAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.Collection;

/**
 * User: Mykhaylo Komarichyn
 * Date: 31.12.2009
 * Time: 12:42:29
 */
public class FileManager extends BaseAction {
    private static final long serialVersionUID = 1302459122285810351L;
    private static final Logger log = LoggerFactory.getLogger(FileManager.class);
    private String command;
    private String type;
    private String currentFolder;
    private String uuid;
    private File newFile;
    private String newFileContentType;
    private String newFileFileName;
    private String newFolderName;

//    private File file;
    private String contentType;
    private String uploadContentType;
    private String filename;
    private Long id;


    @Autowired
    private IFileService<Long> fileService;

    @Override
    public String execute() throws Exception {
        if ("FileUpload".equals(getCommand())) {
            upload();
            return null;
        }
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("text/xml; charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        PrintWriter out = response.getWriter();

        String currentPath = "/" + getType() + getCurrentFolder();
        HttpServletRequest request = ServletActionContext.getRequest();


        Document document = null;
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.newDocument();
        } catch (ParserConfigurationException pce) {
            pce.printStackTrace();
        }

        Node root = createCommonXml(document, getCommand(), getType(), getCurrentFolder(), request.getContextPath() + currentPath);


        if ("GetFolders".equals(getCommand())) {
            getFolders(currentPath, root, document);
        } else if ("GetFoldersAndFiles".equals(getCommand())) {
            getFolders(currentPath, root, document);
            getFiles(currentPath, root, document, request.getContextPath());
        } else if ("CreateFolder".equals(getCommand())) {
            String retValue = "110";
            if (!fileService.isFolderEmpty(currentPath + getNewFolderName())) {
                retValue = "101";
            } else {
                IFile<Long> file = fileService.createBlank();
                file.setFolder(currentPath + getNewFolderName());
                fileService.save(file);
                retValue = "0";
            }
            setCreateFolderResponse(retValue, root, document);
        }
        if (document != null)
            document.getDocumentElement().normalize();
        try {
            TransformerFactory tFactory = TransformerFactory.newInstance();
            Transformer transformer = tFactory.newTransformer();

            DOMSource source = new DOMSource(document);

            StreamResult result = new StreamResult(out);
            transformer.transform(source, result);


            StreamResult dbgResult = new StreamResult(System.out);
            transformer.transform(source, dbgResult);
            log.debug("--- END DOGET ---");


        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }


        out.flush();
        out.close();


        return null;
    }

    public String upload() throws Exception {
        HttpServletResponse response = ServletActionContext.getResponse();

        response.setContentType("text/html; charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        PrintWriter out = response.getWriter();


        String currentPath = "/" + getType() + getCurrentFolder();

        String retVal = "0";
        String newName = "";

        if (!"FileUpload".equals(getCommand()))
            retVal = "203";
        else {

            try {

                String fileNameLong = getNewFileFileName();
                fileNameLong = fileNameLong.replace('\\', '/');
                String[] pathParts = fileNameLong.split("/");
                String fileName = pathParts[pathParts.length - 1];

                String nameWithoutExt = getNameWithoutExtension(fileName);
                String ext = getExtension(fileName);

                int counter = 1;
                while (fileService.exists(fileName, currentPath)) {
                    newName = nameWithoutExt + "(" + counter + ")" + "." + ext;
                    retVal = "201";
                    fileName = newName;
                    counter++;
                }
                IFile<Long> file = fileService.createBlank();
                file.setName(fileName);
                file.setType(getType());
                file.setFolder(currentPath);
                file.setContentType(getNewFileContentType());
                file.setFile(getBytesFromFile(getNewFile()));

                fileService.save(file);

            } catch (Exception ex) {
                retVal = "203";
                log.error(ex.getMessage(), ex);
            }

        }

        out.println("<script type=\"text/javascript\">");
        out.println("window.parent.frames['frmUpload'].OnUploadCompleted(" + retVal + ",'" + newName + "');");
        out.println("</script>");
        out.flush();
        out.close();

        return null;

    }


    protected void getFiles(String dir, Node root, Document doc, String contextPath) {
        Element files = doc.createElement("Files");
        root.appendChild(files);
        Collection<IFile<Long>> fileList = fileService.getFiles(dir);
        for (IFile file : fileList) {
            if (StringUtils.isNotEmpty(file.getName())) {
                Element myEl = doc.createElement("File");
                myEl.setAttribute("name", file.getName());
                myEl.setAttribute("url", contextPath + "/utils/loadFile.action?id=" + file.getId());
                myEl.setAttribute("size", "" + file.getFile().length / 1024);
                files.appendChild(myEl);
            }
        }
    }


    protected void getFolders(String dir, Node root, Document doc) {
        Element folders = doc.createElement("Folders");
        root.appendChild(folders);
        Collection<String> flds = fileService.getFolders(dir);
        for (String folderName : flds) {
            Element myEl = doc.createElement("Folder");
            myEl.setAttribute("name", folderName);
            folders.appendChild(myEl);
        }
    }


    public byte[] getBytesFromFile(File file) throws IOException {
        if (file == null) {
            throw new IOException("file not found");
        }
        InputStream is = new FileInputStream(file);


        // Get the size of the file
        long length = file.length();

        if (length > Integer.MAX_VALUE) {
            // File is too large
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int) length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
                && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }

        // Close the input stream and return bytes

        is.close();

        return bytes;
    }

    public String load() throws Exception {
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setHeader("Cache-Control", "no-cache");
        IFile file = fileService.getFile(getId());
        response.setContentType(file.getContentType());
        response.getOutputStream().write(file.getFile());
        return null;
    }


    protected void setCreateFolderResponse(String retValue, Node root, Document doc) {
        Element myEl = doc.createElement("Error");
        myEl.setAttribute("number", retValue);
        root.appendChild(myEl);
    }


    protected void getFolders(File dir, Node root, Document doc) {
        Element folders = doc.createElement("Folders");
        root.appendChild(folders);
        File[] fileList = dir.listFiles();
        for (File aFileList : fileList) {
            if (aFileList.isDirectory()) {
                Element myEl = doc.createElement("Folder");
                myEl.setAttribute("name", aFileList.getName());
                folders.appendChild(myEl);
            }
        }
    }

    protected void getFiles(File dir, Node root, Document doc) {
        Element files = doc.createElement("Files");
        root.appendChild(files);
        File[] fileList = dir.listFiles();
        for (File aFileList : fileList) {
            if (aFileList.isFile()) {
                Element myEl = doc.createElement("File");
                myEl.setAttribute("name", aFileList.getName());
                myEl.setAttribute("size", "" + aFileList.length() / 1024);
                files.appendChild(myEl);
            }
        }
    }

    protected Node createCommonXml(Document doc, String commandStr, String typeStr, String currentPath, String currentUrl) {

        Element root = doc.createElement("Connector");
        doc.appendChild(root);
        root.setAttribute("command", commandStr);
        root.setAttribute("resourceType", typeStr);

        Element myEl = doc.createElement("CurrentFolder");
        myEl.setAttribute("path", currentPath);
        myEl.setAttribute("url", currentUrl);
        root.appendChild(myEl);

        return root;

    }

    /*
    * This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489
    */

    protected static String getNameWithoutExtension(String fileName) {
        return fileName.substring(0, fileName.lastIndexOf("."));
    }

    /*
    * This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489
    */

    protected String getExtension(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }


    public String getCommand() {
        return command;
    }

    public void setCommand(String command) {
        this.command = command;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getCurrentFolder() {
        return StringUtils.isEmpty(currentFolder) ? "" : currentFolder;
    }

    public void setCurrentFolder(String currentFolder) {
        this.currentFolder = currentFolder;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public File getNewFile() {
        return newFile;
    }

    public void setNewFile(File newFile) {
        this.newFile = newFile;
    }

    public String getNewFileContentType() {
        return newFileContentType;
    }

    public void setNewFileContentType(String newFileContentType) {
        this.newFileContentType = newFileContentType;
    }

    public String getNewFileFileName() {
        return newFileFileName;
    }

    public void setNewFileFileName(String newFileFileName) {
        this.newFileFileName = newFileFileName;
    }

    public String getNewFolderName() {
        return newFolderName;
    }

    public void setNewFolderName(String newFolderName) {
        this.newFolderName = newFolderName;
    }


    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getUploadContentType() {
        return uploadContentType;
    }

    public void setUploadContentType(String uploadContentType) {
        this.uploadContentType = uploadContentType;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}


